using UnityEngine;

public class TableCollisionHandler : CollisionHandlerBase
{
	private static TableCollisionHandler _instance;

	public static TableCollisionHandler instance
	{
		get
		{
			if (_instance == null)
			{
				_instance = new TableCollisionHandler();
			}
			return _instance;
		}
	}

	public override CollisionBallParams MotionParamsAfterCollision(CollisionBallParams initialParams, float mass, float radius)
	{
		return VelocityAfterCollisionWithFriction(initialParams, mass, radius);
	}

	public CollisionBallParams VelocityAfterCollisionFrictionless(CollisionBallParams initialParams, float mass, float radius)
	{
		CollisionBallParams result = default(CollisionBallParams);
		result.position = initialParams.position;
		result.angularVelocity = initialParams.angularVelocity;
		float impulseForCollision = GetImpulseForCollision(initialParams, mass);
		result.velocity = initialParams.velocity + impulseForCollision * Vector3.up / mass;
		return result;
	}

	private float GetImpulseForCollision(CollisionBallParams initialParams, float mass)
	{
		return -1f * initialParams.velocity.y * (BallFlightConstants.instance.coeffRestitution + 1f) / (1f / mass);
	}

	public CollisionBallParams VelocityAfterCollisionWithFriction(CollisionBallParams initialParams, float mass, float radius)
	{
		CollisionBallParams result = default(CollisionBallParams);
		result.position = initialParams.position;
		result.velocity = initialParams.velocity + GetVelocityFromBounce(initialParams, mass) + GetVelocityFromFriction(initialParams, mass, radius) + GetVelocityFromSpin(initialParams, mass, radius);
		result.angularVelocity = initialParams.angularVelocity + GetAngularVelFromFriction(initialParams, mass, radius);
		return result;
	}

	private Vector3 GetVelocityFromBounce(CollisionBallParams initialParams, float mass)
	{
		float impulseForCollision = GetImpulseForCollision(initialParams, mass);
		return impulseForCollision * Vector3.up / mass;
	}

	private Vector3 GetVelocityFromFriction(CollisionBallParams initialParams, float mass, float radius)
	{
		float impulseForCollision = GetImpulseForCollision(initialParams, mass);
		Vector3 tangentToCollisionSurface = GetTangentToCollisionSurface(initialParams, radius);
		return (0f - BallFlightConstants.instance.coeffFriction) * Mathf.Abs(impulseForCollision) * tangentToCollisionSurface / mass;
	}

	private Vector3 GetAngularVelFromFriction(CollisionBallParams initialParams, float mass, float radius)
	{
		float impulseForCollision = GetImpulseForCollision(initialParams, mass);
		Vector3 tangentToCollisionSurface = GetTangentToCollisionSurface(initialParams, radius);
		float momentOfInertia = GetMomentOfInertia(mass, radius);
		return -Vector3Ex.LeftHandCross(Vector3.down * radius, BallFlightConstants.instance.coeffFriction * Mathf.Abs(impulseForCollision) * tangentToCollisionSurface) / momentOfInertia;
	}

	private Vector3 GetVelocityFromSpin(CollisionBallParams initialParams, float mass, float radius)
	{
		float hysteresisOffset = GetHysteresisOffset(radius);
		Vector3 vector = GetRadialVelocity(initialParams.angularVelocity, radius).OnGround();
		return (0f - hysteresisOffset) * vector / mass;
	}

	private Vector3 GetTangentToCollisionSurface(CollisionBallParams initialParams, float radius)
	{
		Vector3 radialVelocity = GetRadialVelocity(initialParams.angularVelocity, radius);
		return (initialParams.velocity.OnGround() + radialVelocity.OnGround()).normalized;
	}

	private Vector3 GetRadialVelocity(Vector3 angularVelocity, float radius)
	{
		return Vector3Ex.LeftHandCross(angularVelocity, Vector3.up * radius);
	}

	private float GetMomentOfInertia(float mass, float radius)
	{
		return 2f * mass * radius * radius / 3f;
	}

	private float GetHysteresisOffset(float radius)
	{
		return radius * BallFlightConstants.instance.hysteresisFactor;
	}

	private float LinearKineticEnergyChange(Vector3 initialVel, Vector3 finalVel, float mass)
	{
		return GetLinearKineticEnergy(finalVel, mass) - GetLinearKineticEnergy(initialVel, mass);
	}

	private float GetLinearKineticEnergy(Vector3 velocity, float mass)
	{
		return 0.5f * mass * Vector3.Dot(velocity, velocity);
	}

	private float GetTotalEnergy(CollisionBallParams ballParams, float mass, float momentOfInertia)
	{
		float num = 0.5f * Vector3.Dot(ballParams.velocity, ballParams.velocity) * mass;
		float num2 = 0.5f * Vector3.Dot(ballParams.angularVelocity, ballParams.angularVelocity) * momentOfInertia;
		return num + num2;
	}
}
